package com.kehutong.repair.service.app;

import java.text.DecimalFormat;
import java.time.Duration;
import java.time.LocalDateTime;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;

import org.coraframework.inject.Inject;
import org.coraframework.json.JSONObject;
import org.coraframework.logger.Logger;
import org.coraframework.logger.LoggerFactory;
import org.coraframework.mvc.http.ReqMapping;
import org.coraframework.mvc.http.result.Result;
import org.coraframework.mvc.webservice.WebService;
import org.coraframework.orm.Pool;
import org.coraframework.orm.jdbc.JdbcSession;
import org.coraframework.orm.jdbc.Page;
import org.coraframework.orm.jdbc.execute.entity.FindArray;
import org.coraframework.orm.jdbc.execute.entity.FindPage;
import org.coraframework.threadpool.ThreadPool;
import org.coraframework.util.Objects;

import com.kehutong.common.DoveClient;
import com.kehutong.common.util.Token;
import com.kehutong.repair.entity.Remark;
import com.kehutong.repair.entity.Repairs;
import com.kehutong.repair.entity.RepairsType;
import com.kehutong.repair.entity.RollOutDetail;
import com.kehutong.repair.enums.RepairsStatus;
import com.kehutong.repair.enums.Source;
import com.kehutong.repair.utils.RepairsUtils;
import com.kehutong.repair.utils.SendMessageUtils;

@WebService("/repairs/app/service")
public class AppRepairsService {

    protected final Logger logger = LoggerFactory.getLogger(AppRepairsService.class);

    @Inject
    private DoveClient doveClient;

    @Inject
    private JdbcSession jdbcSession;

    @Inject
    private SendMessageUtils sendMessageUtils;

    @Inject
    private ThreadPool threadPool;

    @ReqMapping("/count")
    public Object count(Token token, JSONObject jsonObject) {
        final JSONObject result = new JSONObject();
        String[] countValue = {"pending", "processing", "evaluate", "complete"};
        for (int i = 0; i < countValue.length; i++) {
            jsonObject.put("repairsStatus", String.valueOf(i + 1));
            List<Repairs> repairs = getRepairs(token, jsonObject);
            result.put(countValue[i], repairs.size());
            if(i == 0){
                setNotOrderCount(repairs, result);
            }
            if(i == 1){
                setNotCompletedAnd7dCount(repairs, result);
            }
        }
        result.put("username", token.getUsername());
        return result;
    }

    @ReqMapping("/countMore")
    public Object countMore(Token token, JSONObject jsonObject) {
        final JSONObject result = new JSONObject();
        // 平均满意度
        jsonObject.put("repairsStatus", RepairsStatus.COMPLETE.getId());
        List<Repairs> repairs = getRepairs(token, jsonObject);
        DecimalFormat df = new DecimalFormat("0.00");//格式化小数
        int all = 0;
        for (int i = 0; i < repairs.size(); i++) {
            all = repairs.get(i).getTotal() + repairs.get(i).getAttitude() + repairs.get(i).getSpeed();
        }
        String starRate = df.format((float)all/(3 + repairs.size()));//返回String类型
        result.put("starRate", starRate);

        // 累计时长 & 均单时长
        jsonObject.put("repairsStatus", RepairsStatus.EVALUATION.getId());
        repairs.addAll(getRepairs(token, jsonObject));
        long cumulativeTime = 0;
        for (int i = 0; i < repairs.size(); i++) {
            Duration duration = Duration.between(repairs.get(i).getAssignTime(), repairs.get(i).getCompleteTime());
            cumulativeTime+=duration.toHours();
        }
        String aveTime = df.format((float)cumulativeTime/repairs.size());//返回String类型
        if(repairs.size() == 0){
            aveTime = "0.00";
        }
        result.put("cumulativeTime", cumulativeTime);
        result.put("aveTime", aveTime);

        return result;
    }

    @ReqMapping("/list")
    public Page<Repairs> list(Token token, JSONObject jsonObject) {
        // 已开始处理
        if (Integer.valueOf(RepairsStatus.PENDING.getId()) < jsonObject.getIntValue("repairsStatus")
                && jsonObject.getIntValue("repairsStatus") < Integer.valueOf(RepairsStatus.CANCEL.getId())){
            jsonObject.put("employeeNo", token.getUuid());
        }

        Page<Repairs> repairs = null;
        FindPage<Repairs> array = jdbcSession.findPage(Repairs.class)
                .eq(jsonObject, "companyNo", "type", "employeeNo")
                .eq("deleted", false);

        // 处理完
        if (Objects.equal(jsonObject.getString("repairsStatus"), RepairsStatus.EVALUATION.getId())) {
            String[] repairsStatus = {RepairsStatus.COMPLETE.getId(), RepairsStatus.EVALUATION.getId()};
            array = array.in("repairsStatus", Arrays.asList(repairsStatus));
        }else {
            if (Objects.nonEmpty(jsonObject.getString("repairsStatus"))) {
                array = array.eq("repairsStatus", jsonObject.getString("repairsStatus"));
            }
        }

        // 排序
        JSONObject sort = jsonObject.getJSONObject("sort");
        if (Objects.nonEmpty(sort.getString("key"))) {
            array = array.order(sort.getString(("key")), sort.getString(("value")));
        }

        // 我关注的
        if (Objects.isEmpty(jsonObject.getString("repairsStatus"))) {
            array = array.like("attnEmployeeNo", token.getUuid());
        }

        // 待执行
        if (Objects.equal(jsonObject.getString("repairsStatus"), RepairsStatus.PENDING.getId())) {
            array = array.like("exeEmployeeNo", token.getUuid());
        }

        repairs = array.page(jsonObject).exe();
        repairs.getList().forEach(this::setOtherProperty);
        return repairs;
    }

    @ReqMapping("/accept")
    public Object acceptRepairs(Token token, String id) throws Exception {
        Repairs repairs = Pool.get(Repairs.class, id);
        if (Objects.isNull(repairs)) {
            return Result.error(0, "对象不存在");
        }

        repairs.setRepairsStatus(RepairsStatus.PROCESSING);
        repairs.setEmployeeNo(token.getUuid());

        // 移除执行人
        List<String> exeEmployeeNo = repairs.getExeEmployeeNo();
        exeEmployeeNo.remove(token.getUuid());

        // 添加关注人
        List<String> attnEmployeeNo = repairs.getAttnEmployeeNo();
        attnEmployeeNo.addAll(exeEmployeeNo);

        repairs.setExeEmployeeNo(null);
        repairs.setAttnEmployeeNo(attnEmployeeNo);

        repairs.setAssignTime(LocalDateTime.now());

        jdbcSession.updateById(repairs);

        // 记录操作
        JSONObject jsonObject = new JSONObject();
        jsonObject.put("repairsId", repairs.getId());
        jsonObject.put("userId", token.getUserId());
        RollOutDetail rollOutDetail = getNewRollOutDetail(jsonObject);
        rollOutDetail.setRemark("受理了");
        rollOutDetail.setRepairsId(id);
        jdbcSession.insert(rollOutDetail);

//        String title = "您的" + repairs.getType().getDesc() + "已经开始处理！";

        if (repairs.getSource() == Source.APP) {
            // TODO 模板消息
//            Employee employee = Pool.get(Employee.class, repairs.getCreateById());
//            sendMessageTemplateByUserId(repairs, employee.getUserid());
        }
        if (repairs.getSource() == Source.WECHAT_OFFICIAL_ACCOUNT) {
            // TODO 模板消息
//            Set<String> userIds = getUserIds(token, repairs);
//            if (userIds != null) {
//                sendMessageTemplateByUserId(repairs, String.join("|", userIds));
//            }
//
//            //发公众号模板消息
//            threadPool.execute(() -> {
//                sendMessageUtils.sendWeChatMessageTemplate(repairs.getCompanyNo(), repairs, 1);
//            });
        }
        return repairs;
    }

    @ReqMapping("/change")
    public Object change(Token token, JSONObject jsonObject) throws Exception {
        Repairs repairs = Pool.get(Repairs.class, jsonObject.getString("id"));

        if(!Objects.equal(repairs.getRepairsStatus(), RepairsStatus.PENDING)){
            return Result.error(0, "不可转单");
        }

        String recipientId = jsonObject.getString("recipientId");
        List<String> exeEmployeeNo = repairs.getExeEmployeeNo();
        exeEmployeeNo.remove(token.getUserId());
        exeEmployeeNo.add(recipientId);
        repairs.setExeEmployeeNo(exeEmployeeNo);

        // 关注人
        List<String> attnEmployeeNo = repairs.getAttnEmployeeNo();
        attnEmployeeNo.add(token.getUserId());
        repairs.setAttnEmployeeNo(attnEmployeeNo);

        jdbcSession.updateById(repairs);

        // 记录操作
        jsonObject.put("repairsId", repairs.getId());
        jsonObject.put("userId", token.getUserId());// todo id
        jsonObject.put("companyNo", token.getCompanyNo());
        RollOutDetail newRollOutDetail = getNewRollOutDetail(jsonObject);
        newRollOutDetail.setNewEmployeeNo(recipientId);
        JSONObject employeeJSONObject = getEmployeeById(token.getCompanyNo(), recipientId);
        newRollOutDetail.setNewEmployeeName(employeeJSONObject.getString("name"));
        newRollOutDetail.setRemark("转执行人");
        newRollOutDetail.setRepairsId(jsonObject.getString("id"));
        jdbcSession.insert(newRollOutDetail);

//        sendMessageTemplateByUserId(repairs, token.getUuid());// TODO 模板消息

        return Result.success();
    }

    @ReqMapping("/remark")
    public Object remark(Token token, String remark, String id) throws Exception {
        Remark item = Pool.newInstance(Remark.class);
        item.setOrderId(id);
        item.setContent(remark);
        item.setRemarkName(token.getUsername());
        item.setRemarkNameId(token.getUuid());
        jdbcSession.insert(item);

        // 记录操作
        JSONObject jsonObject = new JSONObject();
        jsonObject.put("repairsId", id);
        jsonObject.put("userId", token.getUuid());
        jsonObject.put("companyNo", token.getCompanyNo());
        RollOutDetail newRollOutDetail = getNewRollOutDetail(jsonObject);
        newRollOutDetail.setRepairsId(id);
        newRollOutDetail.setRemark("备注了");
        jdbcSession.insert(newRollOutDetail);

        Repairs repairs =  Pool.get(Repairs.class, id);
        if (repairs.getSource() == Source.WECHAT_OFFICIAL_ACCOUNT) {
            //TODO 发公众号模板消息
//            threadPool.execute(() -> {
//                try {
//                    sendMessageUtils.sendWeChatMessageTemplate(repairs.getCompanyNo(), repairs, 0);
//                } catch (Exception e) {
//                    e.printStackTrace();
//                    logger.error("发公众号模板消息出错：{}", e);
//                }
//            });
        }

        // 发送企微消息模板//TODO 发公众号模板消息
//        Set<String> userIds = new HashSet<>();
//        List<String> employeeNos = repairs.getAttnEmployeeNo();
//        if (Objects.equal(repairs.getRepairsStatus(), RepairsStatus.PENDING)) {
//            employeeNos.addAll(repairs.getExeEmployeeNo());
//            employeeNos.remove(token.getUserId());
//        }
//
//        //String title = "您的" + repairs.getType().getDesc() + "工单追加了一条记录！";
//        if(Objects.nonEmpty(employeeNos)) {
//            List<Employee> employees = jdbcSession.findArray(Employee.class)
//                    .eq("companyNo", token.getCompanyNo())
//                    .eq("deleted", false)
//                    .in("id", employeeNos).exe();
//            employees.forEach(employee -> {
//                userIds.add(employee.getUserid());
//            });
//            if (repairs.getSource() == Source.APP) {
//                Employee employee = Pool.get(Employee.class, repairs.getCreateById());
//                userIds.add(employee.getUserid());
//            }
//            sendMessageTemplateByUserId(repairs, String.join("|", userIds));
//        }

        return Result.success();
    }

    /**
     * 获取报修列表
     *
     * @param jsonObject
     * @return
     */
    private List<Repairs> getRepairs(Token token, JSONObject jsonObject) {
        // 已开始处理
        if(!Objects.equal(jsonObject.getString("repairsStatus"), RepairsStatus.PENDING.getId())){
            jsonObject.put("employeeNo", token.getUuid());
        }

        FindArray<Repairs> findArray = jdbcSession.findArray(Repairs.class)
                .eq(jsonObject, "repairsStatus", "companyNo", "type", "employeeNo")
                .eq("deleted", false);

        // 待处理
        if(Objects.equal(jsonObject.getString("repairsStatus"), RepairsStatus.PENDING.getId())){
            findArray.like("exeEmployeeNo", token.getUuid());
        }

        return findArray.exe();
    }

    /**
     * 设置超12h未接单&超24小时未接单
     *
     * @param repairs
     * @param jsonObject
     */
    private void setNotOrderCount(List<Repairs> repairs, JSONObject jsonObject) {
        AtomicInteger timeOut24hNotOrder = new AtomicInteger();
        AtomicInteger timeOut12hNotOrder = new AtomicInteger();
        repairs.forEach(repair -> {
            Duration duration = Duration.between(repair.getTimeOut(), LocalDateTime.now());
            if (duration.toHours() >= 12) {
                timeOut12hNotOrder.getAndIncrement();
            }
            if (duration.toHours() >= 24) {
                timeOut24hNotOrder.getAndIncrement();
            }
        });
        jsonObject.put("timeOut24hNotOrder", timeOut24hNotOrder);
        jsonObject.put("timeOut12hNotOrder", timeOut12hNotOrder);
    }

    /**
     * 设置超7d未完成总量&超时未完成总量
     *
     * @param repairs
     * @param jsonObject
     */
    private void setNotCompletedAnd7dCount(List<Repairs> repairs, JSONObject jsonObject) {
        AtomicInteger timeOutNotCompleted = new AtomicInteger();
        AtomicInteger timeOut7dNotCompleted = new AtomicInteger();
        repairs.forEach(repair -> {
            String countdown = RepairsUtils.getCountdown(repair);
            if (countdown.contains("超时")) {
                timeOutNotCompleted.getAndIncrement();
            }
            if (countdown.contains("超时7天")) {
                timeOut7dNotCompleted.getAndIncrement();
            }
        });
        jsonObject.put("timeOutNotCompleted", timeOutNotCompleted);
        jsonObject.put("timeOut7dNotCompleted", timeOut7dNotCompleted);
    }

    /**
     * 设置工单的其他属性
     *
     * @param repairs
     */
    private void setOtherProperty(Repairs repairs) {
        RepairsType repairsType = Pool.get(RepairsType.class, repairs.getTypeId());
        repairs.setTime(RepairsUtils.jointTime(repairsType));
        repairs.setCountdown(RepairsUtils.getCountdown(repairs));
    }

    /**
     * 获取处理进度对象
     * @return
     */
    private RollOutDetail getNewRollOutDetail(JSONObject jsonObject) throws Exception {
        RollOutDetail rollOutDetail = Pool.newInstance(RollOutDetail.class);
        rollOutDetail.setRepairsId(jsonObject.getString("repairsId"));
        rollOutDetail.setOldEmployeeNo(jsonObject.getString("userId"));
        JSONObject employeeJSONObject = getEmployeeById(jsonObject.getString("companyNo"), jsonObject.getString("userId"));
        rollOutDetail.setOldEmployeeName(employeeJSONObject.getString("name"));

        return rollOutDetail;
    }

    /**
     * 通过id获取员工
     *
     * @param companyNo
     * @param id
     * @return
     * @throws Exception
     */
    private JSONObject getEmployeeById(String companyNo, String id) throws Exception {
        JSONObject object = doveClient.post("/basic/employee/service/get", (http) -> {
            http.addHeader("companyNo", companyNo);
            http.addParam("id", id);
        });
        if (object.getInteger("code") == 200) {
            return object.getJSONObject("data");
        } else {
            logger.error("{}", object.getString("message"));
            return new JSONObject();
        }
    }
}
